﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace DiscoveryLogic.UI.Layouts.Controls
{
    /// <summary>
    /// The CylinderSlider control encapulates 2 cylinders with a slider that moves the top cylinder. Values can be set such as min, max and current values
    /// </summary>
    [TemplatePart(Name = "PART_SliderThumb", Type = typeof(Ellipse))]
    [TemplatePart(Name = "PART_PrincipalTop", Type = typeof(Ellipse))]
    [TemplatePart(Name = "PART_PrincipalBarrel", Type = typeof(Rectangle))]
    [TemplatePart(Name = "PART_PrincipalBase", Type = typeof(Ellipse))]
    [TemplatePart(Name = "PART_InterestTop", Type = typeof(Ellipse))]
    [TemplatePart(Name = "PART_InterestBarrel", Type = typeof(Rectangle))]
    [TemplatePart(Name = "PART_InterestBase", Type = typeof(Ellipse))]
    [TemplatePart(Name = "PART_VerticalSlider", Type = typeof(FrameworkElement))]
    [TemplatePart(Name = "PART_SliderBar", Type = typeof(Path))]
    public class CylinderSlider : Control
    {
        public CylinderSlider()
        {
            DefaultStyleKey = typeof(CylinderSlider);
        }

        #region Private Fields

        private FrameworkElement _verticalSlider;
        private TextBlock _sliderMaxLabel;  // $5000      
        private TextBlock _sliderMinLabel;  // $9000
        private TextBlock _lowValueLabel;   // interest
        private TextBlock _currentValueLabel;  // slider value
        private TextBlock _currentValueDescriptionLabel;
        private TextBlock _lowValueDescriptionLabel;
        private TextBlock _zeroLabel;
        private TextBlock _titleLabel;

        private Path _sliderMinLine;
        private Path _lowValueLine;
        private Path _sliderBar;
        private Path _horizontalBar;
        private Ellipse _sliderThumb;

        private Ellipse _principalTop;
        private Ellipse _principalGlassTop;
        private Rectangle _principalBarrel;
        private Ellipse _principalBase;
        private Ellipse _interestTop;
        private Rectangle _interestBarrel;
        private Ellipse _interestBase;

        // flag indicating mouse right button depressed            
        private bool _isMouseDown = false;

        private double _delta;

        // initial X, Y position of mouse when move event fired
        private double _originMouseX;
        private double _originMouseY;

        // end X, Y position of mouse when move event fired
        private double _currentMouseX;
        private double _currentMouseY;

        #endregion

        #region Dependency Properties

        #region Styling Dependency Properties

        /// <summary>
        /// The brush that applies to the thumb slider
        /// </summary>
        public Brush ThumbBrush
        {
            get { return (Brush)GetValue(ThumbBrushProperty); }
            set { SetValue(ThumbBrushProperty, value); }
        }
        /// <summary>
        /// Dependency property of the ThumBrush
        /// </summary>
        public static readonly DependencyProperty ThumbBrushProperty =
            DependencyProperty.Register("ThumbBrush", typeof(Brush), typeof(CylinderSlider),
                new PropertyMetadata((obj, args) =>
                {
                    CylinderSlider ctl = (CylinderSlider)obj;
                    ctl.SetThumbBrush();
                }));


        /// <summary>
        /// The brush that applies to the top cylinder body and base 
        /// </summary>
        public Brush TopCylinderBodyBrush
        {
            get { return (Brush)GetValue(TopCylinderBodyBrushProperty); }
            set { SetValue(TopCylinderBodyBrushProperty, value); }
        }
        /// <summary>
        /// Dependency property of the TopCylinderBodyBrush
        /// </summary>
        public static readonly DependencyProperty TopCylinderBodyBrushProperty =
            DependencyProperty.Register("TopCylinderBodyBrush", typeof(Brush), typeof(CylinderSlider),
                 new PropertyMetadata((obj, args) =>
                 {
                     CylinderSlider ctl = (CylinderSlider)obj;
                     ctl.SetTopCylinderBodyBrush();
                 }));

        /// <summary>
        /// The brush that applies to the top cylinder roof (top part).
        /// </summary>
        public Brush TopCylinderRoofBrush
        {
            get { return (Brush)GetValue(TopCylinderRoofBrushProperty); }
            set { SetValue(TopCylinderRoofBrushProperty, value); }
        }
        /// <summary>
        /// Dependency property of the TopCylinderRoofBrush
        /// </summary>
        public static readonly DependencyProperty TopCylinderRoofBrushProperty =
            DependencyProperty.Register("TopCylinderRoofBrush", typeof(Brush), typeof(CylinderSlider),
                 new PropertyMetadata((obj, args) =>
                 {
                     CylinderSlider ctl = (CylinderSlider)obj;
                     ctl.SetTopCylinderRoofBrush();
                 }));

        /// <summary>
        /// The brush that applies to the bottom cylinder body and base 
        /// </summary>
        public Brush BottomCylinderBodyBrush
        {
            get { return (Brush)GetValue(BottomCylinderBodyBrushProperty); }
            set { SetValue(BottomCylinderBodyBrushProperty, value); }
        }
        /// <summary>
        /// Dependency property of the BottomCylinderBodyBrush
        /// </summary>
        public static readonly DependencyProperty BottomCylinderBodyBrushProperty =
            DependencyProperty.Register("BottomCylinderBodyBrush", typeof(Brush), typeof(CylinderSlider),
                 new PropertyMetadata((obj, args) =>
                 {
                     CylinderSlider ctl = (CylinderSlider)obj;
                     ctl.SetBottomCylinderBodyBrush();
                 }));

        /// <summary>
        /// The brush that applies to the bottom cylinder roof (top part).
        /// </summary>
        public Brush BottomCylinderRoofBrush
        {
            get { return (Brush)GetValue(BottomCylinderRoofBrushProperty); }
            set { SetValue(BottomCylinderRoofBrushProperty, value); }
        }
        /// <summary>
        /// Dependency property of the BottomCylinderRoofBrush
        /// </summary>
        public static readonly DependencyProperty BottomCylinderRoofBrushProperty =
            DependencyProperty.Register("BottomCylinderRoofBrush", typeof(Brush), typeof(CylinderSlider),
                 new PropertyMetadata((obj, args) =>
                 {
                     CylinderSlider ctl = (CylinderSlider)obj;
                     ctl.SetBottomCylinderRoofBrush();
                 }));

        #endregion

        #region Data Dependency Properties

        /// <summary>
        /// The curreny value of the slide. When the slider moves this value will change.
        /// </summary>
        public double CurrentValue
        {
            get { return (double)GetValue(CurrentValueProperty); }
            set { SetValue(CurrentValueProperty, value); }
        }
        /// <summary>
        /// The dependency property of the CurrentValue
        /// </summary>
        public static readonly DependencyProperty CurrentValueProperty =
                DependencyProperty.Register("CurrentValue", typeof(double), typeof(CylinderSlider),
                    new PropertyMetadata((obj, args) =>
                    {
                        CylinderSlider ctl = (CylinderSlider)obj;
                        if (ctl.CurrentValueLabel != null)
                        {
                            ctl.SetCurrentValueLabel((double)args.NewValue);
                            ctl.SetSlider();
                        }
                        ctl.OnCurrentValueChanged();
                    }));

        /// <summary>
        /// The Low value which represents the interest line
        /// </summary>
        public double LowValue
        {
            get { return (double)GetValue(LowValueProperty); }
            set { SetValue(LowValueProperty, value); }
        }
        /// <summary>
        ///  The dependency property of the LowValue
        /// </summary>
        public static readonly DependencyProperty LowValueProperty =
            DependencyProperty.Register("LowValue", typeof(double), typeof(CylinderSlider),
                new PropertyMetadata((obj, args) =>
                {
                    CylinderSlider ctl = (CylinderSlider)obj;
                    if (ctl.LowValueLabel != null)
                    {
                        ctl.SetLowValueLabel((double)args.NewValue);
                    }
                    ctl.OnLowValueChanged();
                }));

        /// <summary>
        /// The maximum value of the payment
        /// </summary>
        public double MaxPayment
        {
            get { return (double)GetValue(MaxPaymentProperty); }
            set { SetValue(MaxPaymentProperty, value); }
        }
        /// <summary>
        /// The dependency property of the MaxPayment
        /// </summary>
        public static readonly DependencyProperty MaxPaymentProperty =
            DependencyProperty.Register("MaxPayment", typeof(double), typeof(CylinderSlider),
                new PropertyMetadata((obj, args) =>
                {
                    CylinderSlider ctl = (CylinderSlider)obj;
                    if (ctl.SliderMaxLabel != null)
                    {
                        ctl.SetMaxLabelText((double)args.NewValue);
                    }

                    ctl.OnMaxPaymentChanged();
                }));

        /// <summary>
        /// The minimum value of the payment
        /// </summary>
        public double MinPayment
        {
            get { return (double)GetValue(MinPaymentProperty); }
            set { SetValue(MinPaymentProperty, value); }
        }
        /// <summary>
        /// The dependency property of the MinPayment
        /// </summary>
        public static readonly DependencyProperty MinPaymentProperty =
            DependencyProperty.Register("MinPayment", typeof(double), typeof(CylinderSlider),
                new PropertyMetadata((obj, args) =>
                {
                    CylinderSlider ctl = (CylinderSlider)obj;
                    if (ctl.SliderMinLabel != null)
                    {
                        ctl.SetMinLabelText((double)args.NewValue);
                    }
                    ctl.OnMinPaymentChanged();
                }));

        /// <summary>
        /// The title of the slider. Typically underneath it.
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        /// <summary>
        /// The dependency property of the MinPayment
        /// </summary>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(CylinderSlider),
                new PropertyMetadata((obj, args) =>
                {
                    CylinderSlider ctl = (CylinderSlider)obj;
                    if (ctl.TitleLabel != null)
                    {
                        ctl.TitleLabel.Text = args.NewValue.ToString();
                    }
                }));

        /// <summary>
        /// The current value description that will appear on the right of the slider line
        /// </summary>
        public string CurrentValueDescription
        {
            get { return (string)GetValue(CurrentValueDescriptionProperty); }
            set { SetValue(CurrentValueDescriptionProperty, value); }
        }
        /// <summary>
        /// The dependency property of the CurrentValueDescription
        /// </summary>
        public static readonly DependencyProperty CurrentValueDescriptionProperty =
            DependencyProperty.Register("CurrentValueDescription", typeof(string), typeof(CylinderSlider),
                 new PropertyMetadata((obj, args) =>
                 {
                     CylinderSlider ctl = (CylinderSlider)obj;
                     if (ctl.CurrentValueDescriptionLabel != null)
                     {
                         ctl.CurrentValueDescriptionLabel.Text = args.NewValue.ToString();
                     }
                 }));

        /// <summary>
        /// The low value description that will appear on the right of the low value line. Or the top of the bottom cylinder.
        /// </summary>
        public string LowValueDescription
        {
            get { return (string)GetValue(LowValueDescriptionProperty); }
            set { SetValue(LowValueDescriptionProperty, value); }
        }
        /// <summary>
        /// The dependency property of the LowValueDescription
        /// </summary>
        public static readonly DependencyProperty LowValueDescriptionProperty =
            DependencyProperty.Register("LowValueDescription", typeof(string), typeof(CylinderSlider),
                new PropertyMetadata((obj, args) =>
                {
                    CylinderSlider ctl = (CylinderSlider)obj;
                    if (ctl.LowValueDescriptionLabel != null)
                    {
                        ctl.LowValueDescriptionLabel.Text = args.NewValue.ToString();
                    }
                }));

        #endregion

        #region Formatting Dependency Properties

        /// <summary>
        /// The minimum paymment format that will format the value to a currency. Additional text can be given
        /// </summary>
        public string MinPaymentFormat
        {
            get { return (string)GetValue(MinPaymentFormatProperty); }
            set { SetValue(MinPaymentFormatProperty, value); }
        }
        /// <summary>
        /// The dependency property of the MinPaymentFormat
        /// </summary>
        public static readonly DependencyProperty MinPaymentFormatProperty =
              DependencyProperty.Register("MinPaymentFormat", typeof(string), typeof(CylinderSlider),
                   new PropertyMetadata((obj, args) =>
                   {
                       CylinderSlider ctl = (CylinderSlider)obj;
                       ctl.SetMinLabelText(ctl.MinPayment);
                   }));

        /// <summary>
        /// The low value format that will format the value to a currency. Additional text can be given
        /// </summary>
        public string LowValueFormat
        {
            get { return (string)GetValue(LowValueFormatProperty); }
            set { SetValue(LowValueFormatProperty, value); }
        }
        /// <summary>
        /// The dependency property of the LowValueFormat
        /// </summary>
        public static readonly DependencyProperty LowValueFormatProperty =
              DependencyProperty.Register("LowValueFormat", typeof(string), typeof(CylinderSlider),
                  new PropertyMetadata((obj, args) =>
                  {
                      CylinderSlider ctl = (CylinderSlider)obj;
                      ctl.SetLowValueLabel(ctl.LowValue);
                  }));

        /// <summary>
        /// The zero value format that will format the value to a currency. Additional text can be given
        /// </summary>
        public string ZeroValueFormat
        {
            get { return (string)GetValue(ZeroValueFormatProperty); }
            set { SetValue(ZeroValueFormatProperty, value); }
        }
        /// <summary>
        /// The dependency property of the LowValueFormat
        /// </summary>
        public static readonly DependencyProperty ZeroValueFormatProperty =
              DependencyProperty.Register("ZeroValueFormat", typeof(string), typeof(CylinderSlider),
                  new PropertyMetadata((obj, args) =>
                  {
                      CylinderSlider ctl = (CylinderSlider)obj;
                      ctl.SetZeroLabel();
                  }));

        /// <summary>
        /// The max value format that will format the value to a currency. Additional text can be given
        /// </summary>
        public string MaxValueFormat
        {
            get { return (string)GetValue(MaxValueFormatProperty); }
            set { SetValue(MaxValueFormatProperty, value); }
        }
        /// <summary>
        ///  The dependency property of the MaxValueFormat
        /// </summary>
        public static readonly DependencyProperty MaxValueFormatProperty =
              DependencyProperty.Register("MaxValueFormat", typeof(string), typeof(CylinderSlider),
                   new PropertyMetadata((obj, args) =>
                   {
                       CylinderSlider ctl = (CylinderSlider)obj;
                       ctl.SetMaxLabelText(ctl.MaxPayment);
                   }));

        /// <summary>
        /// The current value format that will format the value to a currency. Additional text can be given
        /// </summary>
        public string CurrentValueFormat
        {
            get { return (string)GetValue(CurrentValueFormatProperty); }
            set { SetValue(CurrentValueFormatProperty, value); }
        }
        /// <summary>
        /// The dependency property of the CurrentValueFormat
        /// </summary>
        public static readonly DependencyProperty CurrentValueFormatProperty =
              DependencyProperty.Register("CurrentValueFormat", typeof(string), typeof(CylinderSlider),
                  new PropertyMetadata((obj, args) =>
                  {
                      CylinderSlider ctl = (CylinderSlider)obj;
                      ctl.SetCurrentValueLabel(ctl.CurrentValue);
                  }));
        #endregion

        #endregion

        #region Eventing

        /// <summary>
        /// The event that will get raised when the current value changes
        /// </summary>
        public event RoutedEventHandler CurrentValueChanged = delegate { };

        /// <summary>
        /// The event that will get raised when the max payment changes
        /// </summary>
        public event RoutedEventHandler MaxPaymentChanged = delegate { };

        /// <summary>
        /// The event that will get raised when the min payment changes
        /// </summary>
        public event RoutedEventHandler MinPaymentChanged = delegate { };

        /// <summary>
        /// The event that will get raised when the low value changes
        /// </summary>
        public event RoutedEventHandler LowValueChanged = delegate { };

        protected virtual void OnCurrentValueChanged()
        {
            RaiseEvent(this.CurrentValueChanged);
        }

        protected virtual void OnMaxPaymentChanged()
        {
            RaiseEvent(this.MaxPaymentChanged);
        }

        protected virtual void OnMinPaymentChanged()
        {
            RaiseEvent(this.MinPaymentChanged);
        }

        protected virtual void OnLowValueChanged()
        {
            RaiseEvent(this.LowValueChanged);
        }

        private void RaiseEvent(RoutedEventHandler handler)
        {
            if (handler != null)
            {
                RoutedEventArgs e = new RoutedEventArgs();
                //e.Source = this;
                handler(this, e);
            }
        }

        #endregion

        #region Public Methods and Properties 

        /// <summary>
        /// Apply the template
        /// </summary>
        public override void OnApplyTemplate()
        {
            PrincipalTop = (Ellipse)GetTemplateChild("PrincipalTop");
            PrincipalGlassTop = (Ellipse)GetTemplateChild("PrincipalGlassTop");
            PrincipalBarrel = (Rectangle)GetTemplateChild("PrincipalBarrel");
            PrincipalBase = (Ellipse)GetTemplateChild("PrincipalBase");
            InterestTop = (Ellipse)GetTemplateChild("InterestTop");
            InterestBarrel = (Rectangle)GetTemplateChild("InterestBarrel");
            InterestBase = (Ellipse)GetTemplateChild("InterestBase");

            VerticalSlider = (FrameworkElement)GetTemplateChild("VerticalSlider");
            SliderBar = (Path)GetTemplateChild("SliderBar");

            SliderMaxLabel = (TextBlock)GetTemplateChild("SliderMaxLabel");  // to  most value

            CurrentValueLabel = (TextBlock)GetTemplateChild("CurrentValueLabel"); // formatted principal
            CurrentValueDescriptionLabel = (TextBlock)GetTemplateChild("CurrentValueDescriptionLabel");  // Principal on right

            SliderMinLabel = (TextBlock)GetTemplateChild("SliderMinLabel");  // min payment
            SliderMinLine = (Path)GetTemplateChild("SliderMinLine");

            LowValueLabel = (TextBlock)GetTemplateChild("LowValueLabel");  // formatted interest
            LowValueDescriptionLabel = (TextBlock)GetTemplateChild("LowValueDescriptionLabel"); // Interest label on the right
            LowValueLine = (Path)GetTemplateChild("LowValueLine");
            ZeroLabel = (TextBlock)GetTemplateChild("ZeroLabel");

            TitleLabel = (TextBlock)GetTemplateChild("TitleLabel");

            HorizontalBar = (Path)GetTemplateChild("Horizontal");

            SliderThumb = (Ellipse)GetTemplateChild("SliderThumb");
            
            UpdatePositions();
        }

       
        public Ellipse PrincipalGlassTop
        {
            get { return _principalGlassTop; }
            set { _principalGlassTop = value; }
        }

        public Ellipse PrincipalTop
        {
            get { return _principalTop; }
            set
            {
                _principalTop = value; 
                SetTopCylinderRoofBrush();
            }
        }

        public Rectangle PrincipalBarrel
        {
            get { return _principalBarrel; }
            set
            {
                _principalBarrel = value;
                SetTopCylinderBodyBrush();
            }
        }

        public Ellipse PrincipalBase
        {
            get { return _principalBase; }
            set
            {
                _principalBase = value;
                SetTopCylinderBodyBrush();
            }
        }

        public Ellipse InterestTop
        {
            get { return _interestTop; }
            set
            {
                _interestTop = value;
                SetBottomCylinderRoofBrush();
            }
        }

        public Rectangle InterestBarrel
        {
            get { return _interestBarrel; }
            set
            {
                _interestBarrel = value;
                SetBottomCylinderBodyBrush();
            }
        }

        public Ellipse InterestBase
        {
            get { return _interestBase; }
            set
            {
                _interestBase = value;
                SetBottomCylinderBodyBrush();
            }
        }

        public FrameworkElement VerticalSlider
        {
            get { return _verticalSlider; }
            set
            {
                if (_verticalSlider != null)
                {
                    _verticalSlider.MouseLeftButtonDown -= new MouseButtonEventHandler(_verticalSlider_MouseLeftButtonDown);
                    _verticalSlider.MouseLeftButtonUp -= new MouseButtonEventHandler(_verticalSlider_MouseLeftButtonUp);
                    _verticalSlider.MouseMove -= new MouseEventHandler(_verticalSlider_MouseMove);
                }
                _verticalSlider = value;

                if (_verticalSlider != null)
                {
                    _verticalSlider.MouseLeftButtonDown += new MouseButtonEventHandler(_verticalSlider_MouseLeftButtonDown);
                    _verticalSlider.MouseLeftButtonUp += new MouseButtonEventHandler(_verticalSlider_MouseLeftButtonUp);
                    _verticalSlider.MouseMove += new MouseEventHandler(_verticalSlider_MouseMove);
                }
            }
        }

        public TextBlock SliderMaxLabel
        {
            get { return _sliderMaxLabel; }
            set
            {
                _sliderMaxLabel = value;
                if (_sliderMaxLabel != null)
                {
                    SetMaxLabelText(MaxPayment);
                    UpdatePositions();
                }
            }
        }

        public TextBlock SliderMinLabel
        {
            get { return _sliderMinLabel; }
            set
            {
                _sliderMinLabel = value;
                if (_sliderMinLabel != null)
                {
                    SetMinLabelText(MinPayment);
                }
            }
        }

        public TextBlock CurrentValueLabel
        {
            get { return _currentValueLabel; }
            set
            {
                _currentValueLabel = value;
                if (_currentValueLabel != null)
                {
                    SetCurrentValueLabel(CurrentValue);
                }
            }
        }

        public TextBlock LowValueLabel
        {
            get { return _lowValueLabel; }
            set
            {
                _lowValueLabel = value;
                if (_lowValueLabel != null)
                {
                    SetLowValueLabel(LowValue);
                    UpdatePositions();
                }
            }
        }

        public TextBlock ZeroLabel
        {
            get { return _zeroLabel; }
            set
            {
                _zeroLabel = value;
                if (_zeroLabel != null)
                {
                    SetZeroLabel();
                    UpdatePositions();
                }
            }
        }


        public TextBlock LowValueDescriptionLabel
        {
            get { return _lowValueDescriptionLabel; }
            set
            {
                _lowValueDescriptionLabel = value;
                if (_lowValueDescriptionLabel != null)
                {
                    _lowValueDescriptionLabel.Text = LowValueDescription;
                }
            }
        }

        public TextBlock CurrentValueDescriptionLabel
        {
            get { return _currentValueDescriptionLabel; }
            set
            {
                _currentValueDescriptionLabel = value;
                if (_currentValueDescriptionLabel != null)
                {
                    _currentValueDescriptionLabel.Text = CurrentValueDescription;

                }
            }
        }

        public TextBlock TitleLabel
        {
            get { return _titleLabel; }
            set
            {
                _titleLabel = value;
                if (_titleLabel != null)
                {
                    _titleLabel.Text = Title;
                }
            }
        }


        public Path HorizontalBar
        {
            get { return _horizontalBar; }
            set
            {
                _horizontalBar = value;
                UpdatePositions();
            }

        }

        public Path SliderMinLine
        {
            get { return _sliderMinLine; }
            set
            {
                _sliderMinLine = value;
                UpdatePositions();
            }
        }


        public Path LowValueLine
        {
            get { return _lowValueLine; }
            set
            {
                _lowValueLine = value;
                UpdatePositions();
            }
        }

        public Ellipse SliderThumb
        {
            get { return _sliderThumb; }
            set
            {
                _sliderThumb = value;
                SetThumbBrush();
            }
        }

        public Path SliderBar
        {
            get { return _sliderBar; }
            set { _sliderBar = value; }
        }

        #endregion

        #region Private Methods

        private void SetThumbBrush()
        {
            if (_sliderThumb != null) 
                _sliderThumb.Fill = ThumbBrush;
        }

        private void SetTopCylinderBodyBrush()
        {
            if (_principalBase != null) 
                _principalBase.Fill = TopCylinderBodyBrush;
            if (_principalBarrel != null) 
                _principalBarrel.Fill = TopCylinderBodyBrush;
        }
        private void SetTopCylinderRoofBrush()
        {
            if (_principalTop != null) 
                _principalTop.Fill = TopCylinderRoofBrush;
        }

        private void SetBottomCylinderBodyBrush()
        {
            if (_interestBase != null) 
                _interestBase.Fill = BottomCylinderBodyBrush;
            if (_interestBarrel != null) 
                _interestBarrel.Fill = BottomCylinderBodyBrush;
        }
        private void SetBottomCylinderRoofBrush()
        {
            if (_interestBase != null) 
                _interestBase.Fill = BottomCylinderRoofBrush;
        }

        private void SetMaxLabelText(double value)
        {
            if (_sliderMaxLabel != null)
                _sliderMaxLabel.Text = string.Format(MaxValueFormat, value);
        }

        private void SetMinLabelText(double value)
        {
            if (_sliderMinLabel != null)
                _sliderMinLabel.Text = string.Format(MinPaymentFormat, value);
        }

        private void SetLowValueLabel(double value)
        {
            if (_lowValueLabel != null)
                _lowValueLabel.Text = string.Format(LowValueFormat, value);
        }

        private void SetCurrentValueLabel(double value)
        {
            if (_currentValueLabel != null)
                _currentValueLabel.Text = string.Format(CurrentValueFormat, value);
        }

        private void SetZeroLabel()
        {
            if (_zeroLabel != null)
            {
                double value = 0;
                _zeroLabel.Text = string.Format(ZeroValueFormat, value);
            }
        }

        private void UpdateMaxLabelPosition()
        {
            if (_sliderMaxLabel != null && _sliderBar != null)
            {
                double pos = (double)_sliderBar.GetValue(Canvas.TopProperty);
                _sliderMaxLabel.SetValue(Canvas.TopProperty, pos - (_sliderMaxLabel.ActualHeight / 2));
            }
        }

        private void UpdateMinimunLabelPosition()
        {
            if (_sliderMinLabel != null && _sliderBar != null && _horizontalBar != null)
            {
                double maxPos = (double)_sliderBar.GetValue(Canvas.TopProperty);
                double zeroPos = (double)_horizontalBar.GetValue(Canvas.TopProperty);
                double diff = zeroPos - maxPos;

                double pos = zeroPos - (MaxPayment > 0 ? (MinPayment / MaxPayment) * diff : 0);

                _sliderMinLabel.SetValue(Canvas.TopProperty, pos - (_sliderMinLabel.ActualHeight / 1.5));  // 1.5 so it can avoid low value
                if (_sliderMinLine != null)
                {
                    _sliderMinLine.Opacity = 1;
                    _sliderMinLine.SetValue(Canvas.TopProperty, pos);
                }
                else
                {
                    _sliderMinLine.Opacity = 0;
                }
            }
            else
            {
                if (_sliderMinLine != null)
                {
                    _sliderMinLine.Opacity = 0;
                }
            }
        }

        private void UpdateLowValueLabelPosition()
        {
            if (_lowValueLabel != null && _sliderBar != null && _horizontalBar != null)
            {
                double maxPos = (double)_sliderBar.GetValue(Canvas.TopProperty);
                double zeroPos = (double)_horizontalBar.GetValue(Canvas.TopProperty);
                double diff = zeroPos - maxPos;

                double pos = zeroPos - (MaxPayment > 0 ? (LowValue / MaxPayment) * diff : 0);

                _lowValueLabel.SetValue(Canvas.TopProperty, pos - (_lowValueLabel.ActualHeight / 4));  // 4 so it can avoid min payment
                if (_lowValueLine != null)
                {
                    _lowValueLine.Opacity = 1;
                    _lowValueLine.SetValue(Canvas.TopProperty, pos);
                }
                else
                {
                    _lowValueLine.Opacity = 0;
                }
                if (_lowValueDescriptionLabel != null)
                {
                    _lowValueDescriptionLabel.Opacity = 1;
                    _lowValueDescriptionLabel.SetValue(Canvas.TopProperty, pos - (_lowValueDescriptionLabel.ActualHeight / 2));
                }
                else
                {
                    _lowValueDescriptionLabel.Opacity = 0;
                }

            }
            else
            {
                if (_lowValueLine != null)
                {
                    _lowValueLine.Opacity = 0;
                }
                if (_lowValueDescriptionLabel != null)
                {
                    _lowValueDescriptionLabel.Opacity = 0;
                }
            }
        }

        private void UpdateZeroPosition()
        {
            if (_zeroLabel != null && _horizontalBar != null)
            {
                double pos = (double)_horizontalBar.GetValue(Canvas.TopProperty);
                _zeroLabel.SetValue(Canvas.TopProperty, pos - (_zeroLabel.ActualHeight / 2));
            }
        }

        public void UpdatePositions()
        {
            UpdateMaxLabelPosition();
            UpdateMinimunLabelPosition();
            UpdateLowValueLabelPosition();
            UpdateZeroPosition();
            HideBlockingLabels();
            SetSlider();
        }
 
        private void SetSlider()
        {
            if (SliderBar == null || SliderMinLine == null || HorizontalBar == null || VerticalSlider == null)
                return;

            // Find slider thumb and its dimensions
            double sliderThumbHeight = _sliderThumb == null ? 17.336 : _sliderThumb.ActualHeight;

            double sliderBarMax = (double)SliderBar.GetValue(Canvas.TopProperty) - sliderThumbHeight / 2;
            double sliderBarMin = (double)SliderBar.GetValue(Canvas.TopProperty) + SliderBar.Height - sliderThumbHeight / 2;
            double sliderMinAllowable = (double)SliderMinLine.GetValue(Canvas.TopProperty) - (sliderThumbHeight / 2);

            double maxPos = (double)SliderBar.GetValue(Canvas.TopProperty);
            double zeroPos = (double)HorizontalBar.GetValue(Canvas.TopProperty);
            double diff = zeroPos - maxPos;
            double p = CurrentValue / MaxPayment;

            double deltaY = diff * p;

            double newValue = zeroPos - deltaY - (sliderThumbHeight / 2); // (double)VerticalSlider.GetValue(Canvas.TopProperty) + deltaY;

            //Ensure that slider thumb doesn`t go beyond min or max
            if (newValue < sliderBarMax)
            {
                newValue = sliderBarMax;
            }

            if (newValue > sliderMinAllowable)
            {
                newValue = sliderMinAllowable;
            }

            VerticalSlider.SetValue(Canvas.TopProperty, newValue);

            ResizeTopCylinder();

            // Hide blocking text
            HideBlockingLabels();
        }

        private void SetSliderValue(double deltaY)
        {
            // Find slider thumb and its dimensions
            double sliderThumbHeight = _sliderThumb == null ? 17.336 : _sliderThumb.ActualHeight;

            // Find slider bar and its dimensions

            double sliderBarMax = (double)SliderBar.GetValue(Canvas.TopProperty) - sliderThumbHeight / 2;
            double sliderBarMin = (double)SliderBar.GetValue(Canvas.TopProperty) + SliderBar.Height - sliderThumbHeight / 2;

            double sliderMinAllowable = (double)SliderMinLine.GetValue(Canvas.TopProperty) - (sliderThumbHeight / 2);

            double newValue = (double)VerticalSlider.GetValue(Canvas.TopProperty) + deltaY;

            //Ensure that slider thumb doesn`t go beyond min or max
            if (newValue < sliderBarMax)
            {
                deltaY = sliderBarMax - (double)VerticalSlider.GetValue(Canvas.TopProperty);
            }

            if (newValue > sliderMinAllowable)
            {
                deltaY = sliderMinAllowable - (double)VerticalSlider.GetValue(Canvas.TopProperty);
            }

            //determin what the new value should be!!!
            double maxPos = (double)SliderBar.GetValue(Canvas.TopProperty);
            double zeroPos = (double)HorizontalBar.GetValue(Canvas.TopProperty);
            double diff = zeroPos - maxPos;

            double p = deltaY / diff;
            double incr = MaxPayment * p;

            double value = CurrentValue - incr;

            this._delta = deltaY;

            //Setting the current value will do 2 things... 1 set the label, to be the correct value and 2, position the slider to the correct location.
            //by doing this setting the value externally will shift the slider automatically. :)
            CurrentValue = value;
        }

        private double GetCylinderPosition(double value)
        {
            if (SliderBar == null || HorizontalBar == null) return 0;

            double maxPos = (double)SliderBar.GetValue(Canvas.TopProperty);
            double zeroPos = (double)HorizontalBar.GetValue(Canvas.TopProperty);
            double diff = zeroPos - maxPos;
            double p = value / MaxPayment;
            double cylinderValue = diff * (1 - p);

            return cylinderValue;
        }

        private void ResizeTopCylinder()
        {
            if (InterestBarrel == null || InterestTop == null || InterestBase == null ||
                PrincipalTop == null || PrincipalGlassTop == null || PrincipalBarrel == null || PrincipalBase == null)
                return;


            double topCylinder = GetCylinderPosition(CurrentValue);
            double botCylinder = GetCylinderPosition(LowValue);
            double baseCylinder = (double)InterestBase.GetValue(Canvas.TopProperty);

            PositionCylinderPart(topCylinder, PrincipalTop);
            PositionCylinderPart(topCylinder, PrincipalGlassTop);
            PositionCylinderPart(topCylinder, botCylinder, PrincipalBarrel, 20);
            PositionCylinderPart(botCylinder, PrincipalBase);

            PositionCylinderPart(botCylinder, InterestTop);
            PositionCylinderPart(botCylinder, baseCylinder, InterestBarrel, 20);
            //PositionCylinderPart(baseCylinder, InterestBase);  //Will have no effect but you get the picture

        }

        private void PositionCylinderPart(double top, Ellipse part)
        {
            part.SetValue(Canvas.TopProperty, top);
        }

        private void PositionCylinderPart(double top, double bottom, Rectangle part, double height)
        {
            part.SetValue(Canvas.TopProperty, top + height);
            part.Height = bottom - top > 0 ? bottom - top : 0;
        }

        private void HideBlockingLabels()
        {
            if (CurrentValueLabel != null && VerticalSlider != null)
            {
                double height = CurrentValueLabel.ActualHeight;
                double top = (double)CurrentValueLabel.GetValue(Canvas.TopProperty) + (double)VerticalSlider.GetValue(Canvas.TopProperty);

                HideBlockingLabel(SliderMaxLabel, height, top);
                HideBlockingLabel(SliderMinLabel, height, top);
                HideBlockingLabel(LowValueLabel, height, top);
            }
        }

        private void HideBlockingLabel(TextBlock label, double sliderHeight, double sliderTop)
        {
            if (label != null)
            {
                double labelHeight = label.ActualHeight;
                double labelTop = (double)label.GetValue(Canvas.TopProperty);

                if (labelHeight + labelTop > sliderTop && labelTop < sliderTop + sliderHeight)
                {
                    label.Opacity = 0;
                }
                else
                {
                    label.Opacity = 1;
                }
            }
        }

        #endregion

        #region Dragging

        void _verticalSlider_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _isMouseDown = true;

            _originMouseX = e.GetPosition(null).X;
            _originMouseY = e.GetPosition(null).Y;

            ((FrameworkElement)sender).CaptureMouse();
        }

        void _verticalSlider_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ((FrameworkElement)sender).ReleaseMouseCapture();
            _isMouseDown = false;
        }

        void _verticalSlider_MouseMove(object sender, MouseEventArgs e)
        {
            // If mouse button is still in down position
            if (_isMouseDown)
            {
                // Retrieve current mouse position
                _currentMouseX = e.GetPosition(null).X;
                _currentMouseY = e.GetPosition(null).Y;

                double deltaY = (_currentMouseY - _originMouseY);

                // Set slider thumb position
                SetSliderValue(deltaY);

                // Update the beginning position of the mouse
                _originMouseX = _currentMouseX;
                _originMouseY = _currentMouseY;
            }
        }

        #endregion

    }
}
